package com.lt.flashcard.model.entity;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.zkoss.zkplus.hibernate.HibernateUtil;

import com.lt.flashcard.model.service.AAService;
import com.lt.flashcard.model.service.Repository;

/**
 * Represent a user in system
 * @author ocsen
 * @version 1.0
 * @created 15-Aug-2012 17:03:45
 */
@Entity
@Table(name = "user", uniqueConstraints = {
		@UniqueConstraint(columnNames = "username"),
		@UniqueConstraint(columnNames = "email") })
public class User implements java.io.Serializable {

    private static final long serialVersionUID = 1L;

	private Long id;
	
	/**
	 * Store the username to login to system
	 */
	private String username;
	/**
	 * Store password to login to this system
	 */
	private String password = "";
	private Date created = new Date();
	private Date updated = new Date();
	/**
	 * The login time
	 */
	private Date login;
	private String email = "";
	/**
	 * Max number of blank flashcard of this user
	 */
	private int maxblankflashcard = 500;
	/**
	 * Current blank flashcard of this user
	 */
	private int currentblankflashcard = 500;
	/**
	 * All role of this user
	 */
	private Set<Role> roles = new HashSet<Role>();
	
	private Set<FlashcardSet> flashcardSets = new HashSet<FlashcardSet>(0);
	
	private int block = 1;
	private String activation = "";
	private Date expiredate = null;
	private int knowCards = 0;
	private int knowCards0 = 0;//level 0
	private int knowCards1 = 0;//level 1
	private int knowCards7 = 0;//level 7
	private int unknowCards = 0;
	private int newCards = 0;
	private int blueCoin = 0;
	private int yellowCoin = 15;
	private int totalBlueCoin = 0;
	private String slogan = "";
	private String name = "";
	private Date birthday = null;
	private String language = "";
	private String workplace = "";
	private String interest = "";
	private String facebook = "";
	private String website = "";
	private String avatar = "";
	private int gender = GENDER_UNKNOW;
	private int rank = 100;
	public static final int GENDER_UNKNOW = 0;
	public static final int GENDER_MALE = 1;
	public static final int GENDER_FEMALE = 2;
	private int privacyProfile = PRIVACY_PUBLIC;
	private int privacyJourney = PRIVACY_PUBLIC;
	private int privacyMedal = PRIVACY_PUBLIC;
	private int privacyFriend = PRIVACY_PUBLIC;
	private int privacyFlashcard = PRIVACY_PUBLIC;
	private int privacyLearning = PRIVACY_PUBLIC;
	private int privacyCoin = PRIVACY_PUBLIC;
	private int privacyCompare = PRIVACY_PUBLIC;
	private int privacySendmessage = PRIVACY_PUBLIC;
	private int privacyFriendrequest = PRIVACY_PUBLIC;
	private int privacySeemyfeed = PRIVACY_PUBLIC;
	private int privacySeeotherfeed = PRIVACY_PUBLIC;
	public static final int PRIVACY_PUBLIC = 0;
	public static final int PRIVACY_FRIENDSOFFRIENDS = 1;
	public static final int PRIVACY_FRIEND = 2;
	public static final int PRIVACY_PRIVATE = 3;
	public static final int PRIVACYGROUP_PROFILE = 0; //View profile or not
	public static final int PRIVACYGROUP_JOURNEY = 1; //View journey or not
	public static final int PRIVACYGROUP_MEDAL = 2; //View medal or not
	public static final int PRIVACYGROUP_FRIEND = 3; //View friend or not
	
	private Set<Orderdetail> orderdetails = new HashSet<Orderdetail>(0);
	
	private Set<Learnhistory> learnhistories = new HashSet<Learnhistory>(0);

	protected User() {
	}

	public User(String username, String password, String email) {
		this.setUsername(username);
		this.setPassword(AAService.hashPassword(password));
		this.setEmail(email);
	}

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id", unique = true, nullable = false)
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@Column(name = "username", unique = true, nullable = false, length = 100)
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Column(name = "password", nullable = false, length = 100)
	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "created", nullable = false, length = 0)
	public Date getCreated() {
		return created;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "login", length = 0)
	public Date getLogin() {
		return login;
	}

	public void setLogin(Date login) {
		this.login = login;
	}
	
	@Column(name = "email", unique = true, nullable = false, length = 100)
	public String getEmail() {
		return this.email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
	
	@Column(name = "maxblankflashcard", nullable = false)
	public int getMaxblankflashcard() {
		return this.maxblankflashcard;
	}

	public void setMaxblankflashcard(int maxblankflashcard) {
		this.maxblankflashcard = maxblankflashcard;
	}

	@Column(name = "currentblankflashcard", nullable = false)
	public int getCurrentblankflashcard() {
		return this.currentblankflashcard;
	}

	public void setCurrentblankflashcard(int currentblankflashcard) {
		this.currentblankflashcard = currentblankflashcard;
	}

	@ManyToMany(fetch = FetchType.EAGER)
	@JoinTable(name = "user_has_role", joinColumns = { @JoinColumn(name = "user_id", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
	public Set<Role> getRoles() {
		return this.roles;
	}

	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "updated", nullable = false, length = 0)
	public Date getUpdated() {
		return updated;
	}

	public void setUpdated(Date updated) {
		this.updated = updated;
	}

	@Transient
	public Set<Permission> getPermissions() {
		Session ses = HibernateUtil.currentSession();
		Set<Role> rl = getRoles();
		if(rl == null || rl.size() == 0)
			return new HashSet<Permission>();
		
		Set<Integer> rlid = new HashSet<Integer>();
		for(Role role : rl)
			rlid.add(role.getId());
		
		Criteria crit = ses.createCriteria(Permission.class);
		crit.createAlias("roles", "role");
		crit.add(Restrictions.in("role.id", rlid));
		return new HashSet<Permission>(crit.list());
	}

	@Column(name = "block", nullable = false, length = 4)
	public int getBlock() {
		return block;
	}

	public void setBlock(int block) {
		this.block = block;
	}

	@Column(name = "activation", nullable = false, length = 100)
	public String getActivation() {
		return activation;
	}

	public void setActivation(String activation) {
		this.activation = activation;
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "expiredate", nullable = true, length = 0)
	public Date getExpiredate() {
		return expiredate;
	}

	public void setExpiredate(Date expiredate) {
		this.expiredate = expiredate;
	}

	@Column(name = "knowCards", nullable = false)
	public int getKnowCards() {
		return knowCards;
	}

	public void setKnowCards(int knowCards) {
		this.knowCards = knowCards;
	}
	
	@Column(name = "knowCards0", nullable = false)
	public int getKnowCards0() {
		return this.knowCards0;
	}

	public void setKnowCards0(int knowCards0) {
		this.knowCards0 = knowCards0;
	}

	@Column(name = "knowCards1", nullable = false)
	public int getKnowCards1() {
		return this.knowCards1;
	}

	public void setKnowCards1(int knowCards1) {
		this.knowCards1 = knowCards1;
	}

	@Column(name = "knowCards7", nullable = false)
	public int getKnowCards7() {
		return this.knowCards7;
	}

	public void setKnowCards7(int knowCards7) {
		this.knowCards7 = knowCards7;
	}

	@Column(name = "unknowCards", nullable = false)
	public int getUnknowCards() {
		return unknowCards;
	}

	public void setUnknowCards(int unknowCards) {
		this.unknowCards = unknowCards;
	}

	@Column(name = "newCards", nullable = false)
	public int getNewCards() {
		return newCards;
	}

	public void setNewCards(int newCards) {
		this.newCards = newCards;
	}

	@Column(name = "blueCoin", nullable = false)
	public int getBlueCoin() {
		return blueCoin;
	}

	public void setBlueCoin(int blueCoin) {
		this.blueCoin = blueCoin;
	}

	@Column(name = "yellowCoin", nullable = false)
	public int getYellowCoin() {
		return yellowCoin;
	}

	public void setYellowCoin(int yellowCoin) {
		this.yellowCoin = yellowCoin;
	}

	@Column(name = "totalBlueCoin", nullable = false)
	public int getTotalBlueCoin() {
		return totalBlueCoin;
	}

	public void setTotalBlueCoin(int totalBlueCoin) {
		this.totalBlueCoin = totalBlueCoin;
	}
	
	@Column(name = "slogan", nullable = false)
	public String getSlogan() {
		return this.slogan;
	}

	public void setSlogan(String slogan) {
		this.slogan = slogan;
	}

	@Column(name = "name", nullable = false, length = 100)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Temporal(TemporalType.DATE)
	@Column(name = "birthday", length = 0)
	public Date getBirthday() {
		return this.birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	@Column(name = "language", nullable = false)
	public String getLanguage() {
		return this.language;
	}

	public void setLanguage(String language) {
		this.language = language;
	}

	@Column(name = "workplace", nullable = false)
	public String getWorkplace() {
		return this.workplace;
	}

	public void setWorkplace(String workplace) {
		this.workplace = workplace;
	}

	@Column(name = "interest", nullable = false)
	public String getInterest() {
		return this.interest;
	}

	public void setInterest(String interest) {
		this.interest = interest;
	}

	@Column(name = "facebook", nullable = false, length = 100)
	public String getFacebook() {
		return this.facebook;
	}

	public void setFacebook(String facebook) {
		this.facebook = facebook;
	}

	@Column(name = "website", nullable = false, length = 150)
	public String getWebsite() {
		return this.website;
	}

	public void setWebsite(String website) {
		this.website = website;
	}
	
	@Column(name = "gender", nullable = false)
	public int getGender() {
		return this.gender;
	}

	public void setGender(int gender) {
		this.gender = gender;
	}
	
	@Column(name = "privacy_profile", nullable = false)
	public int getPrivacyProfile() {
		return this.privacyProfile;
	}

	public void setPrivacyProfile(int privacyProfile) {
		this.privacyProfile = privacyProfile;
	}

	@Column(name = "privacy_journey", nullable = false)
	public int getPrivacyJourney() {
		return this.privacyJourney;
	}

	public void setPrivacyJourney(int privacyJourney) {
		this.privacyJourney = privacyJourney;
	}

	@Column(name = "privacy_medal", nullable = false)
	public int getPrivacyMedal() {
		return this.privacyMedal;
	}

	public void setPrivacyMedal(int privacyMedal) {
		this.privacyMedal = privacyMedal;
	}

	@Column(name = "privacy_friend", nullable = false)
	public int getPrivacyFriend() {
		return this.privacyFriend;
	}

	public void setPrivacyFriend(int privacyFriend) {
		this.privacyFriend = privacyFriend;
	}
	
	@Transient
	public String getGenderStr() {
		switch(gender) {
			case GENDER_FEMALE: return "Female";
			case GENDER_MALE: return "Male";
			default: return "Unknow";
		}
	}
	
	@Column(name = "avatar", nullable = false, length = 100)
	public String getAvatar() {
		return this.avatar;
	}

	public void setAvatar(String avatar) {
		this.avatar = avatar;
	}
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
	public Set<Learnhistory> getLearnhistories() {
		return this.learnhistories;
	}

	public void setLearnhistories(Set<Learnhistory> learnhistories) {
		this.learnhistories = learnhistories;
	}
	
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
	public Set<Orderdetail> getOrderdetails() {
		return this.orderdetails;
	}

	public void setOrderdetails(Set<Orderdetail> orderdetails) {
		this.orderdetails = orderdetails;
	}
	
	@Column(name = "privacy_flashcard", nullable = false)
	public int getPrivacyFlashcard() {
		return this.privacyFlashcard;
	}

	public void setPrivacyFlashcard(int privacyFlashcard) {
		this.privacyFlashcard = privacyFlashcard;
	}

	@Column(name = "privacy_learning", nullable = false)
	public int getPrivacyLearning() {
		return this.privacyLearning;
	}

	public void setPrivacyLearning(int privacyLearning) {
		this.privacyLearning = privacyLearning;
	}

	@Column(name = "privacy_coin", nullable = false)
	public int getPrivacyCoin() {
		return this.privacyCoin;
	}

	public void setPrivacyCoin(int privacyCoin) {
		this.privacyCoin = privacyCoin;
	}

	@Column(name = "privacy_compare", nullable = false)
	public int getPrivacyCompare() {
		return this.privacyCompare;
	}

	public void setPrivacyCompare(int privacyCompare) {
		this.privacyCompare = privacyCompare;
	}

	@Column(name = "privacy_sendmessage", nullable = false)
	public int getPrivacySendmessage() {
		return this.privacySendmessage;
	}

	public void setPrivacySendmessage(int privacySendmessage) {
		this.privacySendmessage = privacySendmessage;
	}

	@Column(name = "privacy_friendrequest", nullable = false)
	public int getPrivacyFriendrequest() {
		return this.privacyFriendrequest;
	}

	public void setPrivacyFriendrequest(int privacyFriendrequest) {
		this.privacyFriendrequest = privacyFriendrequest;
	}

	@Column(name = "privacy_seemyfeed", nullable = false)
	public int getPrivacySeemyfeed() {
		return this.privacySeemyfeed;
	}

	public void setPrivacySeemyfeed(int privacySeemyfeed) {
		this.privacySeemyfeed = privacySeemyfeed;
	}

	@Column(name = "privacy_seeotherfeed", nullable = false)
	public int getPrivacySeeotherfeed() {
		return this.privacySeeotherfeed;
	}

	public void setPrivacySeeotherfeed(int privacySeeotherfeed) {
		this.privacySeeotherfeed = privacySeeotherfeed;
	}
	
	@Column(name = "rank", nullable = false)
	public int getRank() {
		return this.rank;
	}

	public void setRank(int rank) {
		this.rank = rank;
	}
	
	private UserConfig _config = null;
	@Transient
	public UserConfig getUserConfig() {
		if(getId() == null)
			return null;
		if(_config == null) {
			_config = Repository.getInstance().getUserService().getUserConfigOfUser(getId());
			if(_config == null) {
				_config = new UserConfig();
				_config.setUserid(getId());
			}
		}
		return _config;
	}
	
	@Transient
	public void saveUserConfig() {
		if(_config != null) {
			Repository.getInstance().getUserService().saveUserConfig(_config);
		}
	}
}